package whsw;

import java.util.Map;
import java.util.Scanner;

/**
 * 步骤五. 定义程序运行的框架, 设计并组织所有的功能
 *
 * ----------------------------------------
 * 整个程序的运行逻辑是 (下面用伪代码说明)
 *
 * while (true) {
 *     input = 读取用户输入()
 *     if (input.是空白输入?)
 *         跳过
 *     if (input.是退出命令?)
 *         退出程序
 *
 *     处理命令行(input)
 * }
 *
 * -----------------------------------------
 * 那么在这个程序中是如何利用-策略工厂-设计模式的呢?
 * @see Handlers#getHandlers() 返回策略工厂Map
 *
 * 首先有策略工厂
 * 策略工厂 = {
 *     "help" => help功能实现
 *     "insert" => insert功能实现
 *     "remove" => remove功能实现
 *     ... ...
 * }
 *
 * 然后有用户输入命令
 * 用户输入 = "remove 1201"
 *
 * 将用户输入的命令和测试工厂进行匹配
 * for (策略 in 策略工厂) {
 *     if (用户输入.startWith(策略.处理范围)) {
 *         策略.处理命令行(用户输入)
 *     }
 * }
 *
 * @author flutterdash@qq.com
 * @since 2021/6/20 13:29
 */
public class Starter {

    static final String prompt = "console> ";

    static final Scanner scanner = new Scanner(System.in);
    static final Employees employees = new Employees();
    static Exception exception;

    public static void run() {
        Map<String, CommandLineHandler> handlers = Handlers.getHandlers();
        String input;

        CommandLineHandler.println(greetings());      // 输出欢迎信息

        while (true) {
            CommandLineHandler.print(prompt);
            input = scanner.nextLine().trim();
            if (input.equals(""))                     // 空输入, 跳过
                continue;
            if (isExitCommand(input))                 // 退出命令, 退出程序
                break;
            if (input.equals("show exception")) {     // 查看异常信息
                showException();
                continue;
            }

            doHandlers(handlers, input);              // 处理命令
        }
    }

    private static String greetings() {
        return
                "控制台版 员工管理系统 by flutterdash@qq.com\n" +
                "     ::系统使用帮助::\n" +
                "输入 help 查看系统所有可用的命令\n\n" +
                "insert 增加员工信息\n" +
                "remove 删除员工信息\n" +
                "update 修改员工信息\n" +
                "select 查看员工信息\n\n" +
                "输入 help <insert|remove|update|select> 查看这些命令的详细用法\n";
    }

    private static boolean isExitCommand(String cmd) {
        return cmd.equals("exit");
    }

    private static void showException() {
        if (exception != null)
            /*
                实际操作发现 System.err.println 会打断 System.out.println 的输出
                造成排版错乱, 影响程序的美观
                所以目前的做法是将所有的 System.err 全部重定向到 System.out
             */
            exception.printStackTrace(System.out);
    }

    private static void doHandlers(Map<String, CommandLineHandler> handlers, String cmd) {
        for (Map.Entry<String, CommandLineHandler> entry : handlers.entrySet()) {
            String key = entry.getKey();
            CommandLineHandler handler = entry.getValue();
            if (cmd.startsWith(key)) {
                doHandler(handler, key, cmd);
                return;
            }
        }

        CommandLineHandler.err("系统不能识别这条命令 `" + cmd + "`");
    }

    private static void doHandler(CommandLineHandler handler, String key, String cmd) {
        cmd = cmd.substring(key.length()).trim();

        try {
            handler.handle(cmd, employees);
        } catch (Exception e) {
            /*
                输出友好的异常信息
             */
            exception = e; // 记录最近一次触发的异常
            CommandLineHandler.err("异常信息: " + e.getMessage());
            CommandLineHandler.err("输入 show exception 查看异常调用栈");
            CommandLineHandler.err("输入 help " + key + " 查看功能用法");
        }
    }

}
